/*
Copyright (C) 2008 raohmaru <http://www.raohmaru.com>

This file is part of Raohmaru AS3 Framework.

Raohmaru AS3 Framework is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Raohmaru AS3 Framework is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with Raohmaru AS3 Framework.  If not, see <http://www.gnu.org/licenses/>.
*/

package jp.raohmaru.effects 
{
import flash.filters.BitmapFilter;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.utils.Timer;

/**
 * Se distribuye cuando ha finalizado la transición.
 * @eventType flash.events.Event.COMPLETE
 */
[Event(name="complete", type="flash.events.Event") ]

/**
 * Transición animada entre dos imágenes con un efecto de disolución de píxeles.
 * @see flash.display.BitmapData#pixelDissolve
 * @see fl.transitions.PixelDissolve
 * @author raohmaru
 * @version 1.5
 */
public class PixelDissolve extends EventDispatcher
{
	private var	_bmd_origin : BitmapData,
				_bmd_destination : BitmapData,
				_bmd_work : BitmapData,
				_numPixels : int,
				_randomNum : Number = Math.floor(Math.random() * int.MAX_VALUE),
				_timer : Timer,
				_filter :BitmapFilter;
				
	private const POINT :Point = new Point();

	/**
	* Define o obtiene el objeto BitmapData de origen. Si la transición se está ejecutando no se puede cambiar.
	*/
	public function get bmdOrigin() :BitmapData
	{
		return _bmd_origin;
	}	
	public function set bmdOrigin(value :BitmapData) :void
	{
		if(!_timer.running) _bmd_origin = value;
	}
	
	/**
	* Define o obtiene el objeto BitmapData de destino. Si la transición se está ejecutando no se puede cambiar.
	*/
	public function get bmdDestination() :BitmapData
	{
		return _bmd_destination;
	}	
	public function set bmdDestination(value :BitmapData) :void
	{
		if(!_timer.running) _bmd_destination = value;
	}
	
	/**
	* Define o obtiene el Número de píxeles que se "disolverán" en cada paso de la transición.
	* @default 4000
	*/
	public function get numPixels() :int
	{
		return _numPixels;
	}	
	public function set numPixels(value :int) :void
	{
		_numPixels = value;
	}
	
	/**
	* Define o obtiene la velocidad de la transición en milisegundos (números altos mayor lentitud).
	* @default 20
	*/
	public function get delay() :Number
	{
		return _timer.delay;
	}	
	public function set delay(value :Number) :void
	{
		_timer.delay = value;
	}

	/**
	 * Define un objeto BitmapFilter a aplicar a la transición de píxeles. En el caso de definir uno, se utilizará el BitmapData de
	 * origen también para el destino, pero sin copiar el canal alpha (crea efectos interesantes cuando se aplica la transición
	 * en un BitmapData de origen con modificaciones en el canal alpha).
	 */
	public function get filter() :BitmapFilter
	{
		return _filter;
	}
	
	public function set filter(value :BitmapFilter) :void
	{
		_filter = value;
	}
	
	/**
	 * Crea una nueva transición entre dos BitmapData.
	 * @param bmd_origin La imagen de mapa de bits de origen que se va a utilizar. Los píxeles se copiarán en esta imagen.
	 * @param bmd_destination La imagen de mapa de bits de destino
	 * @param numPixels Número de píxeles que se "disolverán" en cada paso de la transición
	 * @param delay Velocidad de la transición (números altos mayor lentitud)
	 */
	public function PixelDissolve(bmd_origin : BitmapData, bmd_destination : BitmapData, num_pixels : int = 4000, delay : Number = 20)
	{
		_bmd_origin = bmd_origin;
		_bmd_destination = bmd_destination;
		_numPixels = num_pixels;
		
		_timer = new Timer(delay);
		_timer.addEventListener(TimerEvent.TIMER, doTransition);
	}
	
	/**
	 * Inicia la transición.
	 */
	public function start() : void
	{
		if(!_timer.running)
		{
			_bmd_work = _bmd_origin.clone();
			_timer.start();
		}
	}
	
	/**
	 * Detiene la transición.
	 */
	public function stop() : void
	{
		if(_timer.running)
		{
			_timer.stop();
			_bmd_work.dispose();
		}
	}
	
	private function doTransition(event : TimerEvent) : void
	{
		if(_filter)
		{
			// Aplica la transición a un BitmapData privado, del que luego copiar los píxeles con filtro
			_randomNum = _bmd_work.pixelDissolve(_bmd_destination, _bmd_origin.rect, POINT, _randomNum, _numPixels);
			var nbmd :BitmapData = _bmd_work.clone();
				nbmd.applyFilter(nbmd, nbmd.rect, POINT, _filter);
			
			_bmd_origin.copyPixels(_bmd_destination, _bmd_origin.rect, POINT, nbmd, POINT, true);
		}
		else
			_randomNum = _bmd_origin.pixelDissolve(_bmd_destination, _bmd_origin.rect, POINT, _randomNum, _numPixels);
	   
	   
	   // Comprueba que no queden píxels transparentes (ha acabado la transición)
		var alphaRegion:Rectangle = _bmd_work.getColorBoundsRect(0xFF000000, 0x00000000, true);
		if(alphaRegion.width == 0 && alphaRegion.height == 0)
		{
			_timer.stop();
			_bmd_work.dispose();
			dispatchEvent(new Event(Event.COMPLETE));
		}
	};
}
}